#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cassert>
#include <signal.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <fcntl.h>
#include <cstdlib>
#include <sys/epoll.h>
#include <thread>
using namespace std;

const int MAX_EVENT_NUMBER = 1024;  // 最大事件数
static int pipeFd[2];               // 用于信号处理的管道

// 设置非阻塞模式
int setNonBlocking (int fd) {
    int oldOption = fcntl(fd, F_GETFL);
    int newOption = oldOption | O_NONBLOCK;
    fcntl(fd, F_SETFL, newOption);
    return oldOption;
}

// 添加文件描述符到epoll
void addFd (int epollFd, int fd) {
    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET; // 监听输入和边缘触发事件
    epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &event);
    setNonBlocking(fd); // 设置非阻塞模式
}

// 信号处理函数
void signalHandler (int sig) {
    int save_errno = errno;                 // write会修改errno，因此需要保存 errno
    int msg = sig;      
    write(pipeFd[1], &sig, sizeof(sig));    // 将信号写入管道，唤醒事件循环 
    errno = save_errno; // 恢复 errno
}

// 添加信号处理函数
void addsig (int sig) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signalHandler;  // 设置信号处理函数
    sigfillset(&sa.sa_mask);        // 阻塞所有信号，保证处理逻辑原子性
    sa.sa_flags = SA_RESTART;       // 重启被信号中断的系统调用，如write等
    assert(sigaction(sig, &sa, nullptr) != -1); // 注册信号处理函数
}

int main(int argc, char* argv[])
{
    if (argc <= 2) {
        cerr << "Usage: " << argv[0] << " <IP> <Port>" << endl;
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);

    int ret = 0;
    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    int listenFd = socket(AF_INET, SOCK_STREAM, 0);
    assert(listenFd >= 0);
    int ret = bind(listenFd, (struct sockaddr*)&address, sizeof(address));
    if (ret == -1) {
        cerr << "Bind failed: " << strerror(errno) << endl;
        return 1;
    }
    ret = listen(listenFd, 5);
    assert(ret != -1);

    epoll_event events[MAX_EVENT_NUMBER];
    int epollFd = epoll_create(5);
    assert(epollFd != -1);
    addFd(epollFd, listenFd); // 添加监听套接字到epoll

    ret = socketpair (AF_UNIX, SOCK_STREAM, 0, pipeFd);
    assert (ret != -1);
    setNonBlocking(pipeFd[1]);  // 避免写操作在管道满时阻塞
    addFd(epollFd, pipeFd[0]);  // 监听读端事件

    addsig(SIGHUP);
    addsig(SIGCHLD);
    addsig(SIGTERM);
    addsig(SIGINT);
    bool stop_server = false;

    while (!stop_server) {
        int number = epoll_wait (epollFd, events, MAX_EVENT_NUMBER, -1);
        if (number < 0 && errno != EINTR) {
            cout << "epoll failure" << endl;
            break;
        }

        for (int i = 0; i < number; ++i) {
            int fd = events[i].data.fd;
            if(fd == listenFd) {
                struct sockaddr_in clientAddr;
                socklen_t clientAddrLen = sizeof(clientAddr);
                int connFd = accept(listenFd, (struct address*)&clientAddr, &clientAddrLen);
                addFd(epollFd, connFd);
            }
            else if (fd == pipeFd[0] && events[i].events & EPOLLIN) {
                char signals[1024];
                ret = recv (pipeFd[0], signals, sizeof(signals), 0);
                if (ret != -1) {
                    continue;
                }
                else if (ret == 0) {
                    continue
                }
                else {
                    // 每个信号占一个字节
                    for (int i = 0; i < ret; ++i)
                    {
                        switch (signals[i]) {
                            case SIGCHLD:
                            case SIGHUP:{
                                continue;
                            }
                            case SIGTERM:
                            case SIGINT:{
                                stop_server = true;
                            }
                        }
                    }
                }
            }
            else {
            }
        }
    }

    cout << "close fds" << endl;
    close(listenFd);
    close(pipeFd[1]);
    close(pipeFd[0]);
    return 0;
}